home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 11 / Mac Magazin and MacEasy Magazine CD - Issue 11.iso / Sharewarebibliothek / Entwickler / WASTE 1.1 C / WEInlineInput.c < prev    next >
Text File  |  1995-05-24  |  16KB  |  653 lines

  1. // { WASTE PROJECT: }
  2. // { Inline Input Support }
  3.  
  4. // { Copyright © 1993-1995 Marco Piovanelli }
  5. // { All Rights Reserved }
  6. // C conversion by Dan Crevier
  7.  
  8. #include "WASTEIntf.h"
  9. #include "LongCoords.h"
  10.  
  11. #define myTypeQDPoint 'QDpt'
  12.  
  13. // { static variables }
  14.  
  15. static AEEventHandlerUPP _weUpdateActiveInputAreaHandler = NULL;
  16. static AEEventHandlerUPP _wePositionToOffsetHandler = NULL;
  17. static AEEventHandlerUPP _weOffsetToPositionHandler = NULL;
  18.  
  19. pascal OSErr _WEHiliteRangeArray(TextRangeArrayHandle hTray, WEHandle hWE)
  20. {
  21.     WEPtr pWE;
  22.     TextRangePtr pRange;
  23.     long rangeStart, rangeEnd;
  24.     short hiliteStyle;
  25.     WETextStyle ts;
  26.     short rangeIndex;
  27.     Boolean saveTrayLock;
  28.     OSErr err;
  29.  
  30.     pWE = *hWE;
  31.  
  32.     //{ lock down the range array }
  33.     saveTrayLock = _WESetHandleLock((Handle)hTray, true);
  34.     rangeIndex = (**hTray).fNumOfRanges - 1;
  35.     pRange = (*hTray)->fRange;
  36.  
  37.     //{ walk the hilite range array }
  38.     while (rangeIndex >= 0)
  39.     {
  40.  
  41.         //{ the offsets in the range array are relative to the beginning }
  42.         //{ of the active input area: convert them to absolute offsets }
  43.         rangeStart = pWE->tsmAreaStart + pRange->fStart;
  44.         rangeEnd = pWE->tsmAreaStart + pRange->fEnd;
  45.         hiliteStyle = pRange->fHiliteStyle;
  46.  
  47.         //{ take the absolute value of hiliteStyle }
  48.         hiliteStyle = ABS(hiliteStyle);
  49.  
  50.         //{ if hiliteStyle is kCaretPosition, set the selection range }
  51.         if (hiliteStyle == kCaretPosition)
  52.         {
  53.             pWE->selStart = rangeStart;
  54.             pWE->selEnd = rangeEnd;
  55.         }
  56.         else
  57.         {
  58.             hiliteStyle = hiliteStyle - kRawText;
  59.             //{ otherwise set the WETextStyle flags of the specified range appropriately }
  60.             if ((hiliteStyle >= 0) && (hiliteStyle <= 3))
  61.             {
  62.                 ts.tsFlags = 0x10 + BSL(hiliteStyle, tsTSMSelected);
  63.                 err = _WESetStyleRange(rangeStart, rangeEnd, weDoFlags, &ts, hWE);
  64.                 if (err != noErr)
  65.                 {
  66.                     goto cleanup;
  67.                 }
  68.             }
  69.         }        
  70.         //{ go to next text range element }
  71.         rangeIndex = rangeIndex - 1;
  72.         pRange++;
  73.     }
  74.  
  75.     // { clear result code }
  76.     err = noErr;
  77.  
  78. cleanup:
  79.     //{ unlock the range array }
  80.     _WESetHandleLock((Handle)hTray, saveTrayLock);
  81.  
  82.     return err;
  83. }
  84.  
  85. pascal OSErr _WEHandleUpdateActiveInputArea(AppleEvent *ae, AppleEvent *reply,
  86.         long handlerRefCon)
  87. {
  88. #pragma unused(reply, handlerRefCon)
  89.     WEHandle hWE;
  90.     WEPtr pWE;
  91.     AEDesc text;
  92.     AEDesc hiliteTray;
  93.     TextRange pinRange;
  94.     long totalLength;
  95.     long fixLength;
  96.     long tsmOffset;
  97.     DescType returnedType;
  98.     long actualSize;
  99.     GrafPtr savePort;
  100.     WEActionHandle hAction;
  101.     Boolean saveAutoScroll;
  102.     Boolean saveTextLock;
  103.     Boolean saveWELock;
  104.     OSErr err;
  105.  
  106.     hWE = nil;
  107.  
  108.     //{ initialize descriptors to null values }
  109.     text.descriptorType = typeNull;
  110.     text.dataHandle = nil;
  111.     hiliteTray.descriptorType = typeNull;
  112.     hiliteTray.dataHandle = nil;
  113.  
  114.     //{ extract WE handle }
  115.     err = AEGetParamPtr(ae, keyAETSMDocumentRefcon, typeLongInteger, &returnedType,
  116.         (Ptr)&hWE, sizeof(hWE), &actualSize);
  117.     if (err != noErr)
  118.     {
  119.         goto cleanup;
  120.     }
  121.  
  122.     //{ lock the WE handle }
  123.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  124.     pWE = *hWE;
  125.  
  126.     // { return an error code if this instance is read-only }
  127.     err = weReadOnlyErr;
  128.     if (BTST(pWE->flags, weFReadOnly))
  129.         goto cleanup;
  130.  
  131.     //{ call the pre-update callback, if present }
  132.     if (pWE->tsmPreUpdate != nil)
  133.     {
  134.         CallWETSMPreUpdateProc(hWE, (WETSMPreUpdateUPP)pWE->tsmPreUpdate);
  135.     }
  136.  
  137.     //{ hide the caret if it's showing }
  138.     if (BTST(pWE->flags, weFCaretVisible))
  139.     {
  140.         _WEBlinkCaret(hWE);
  141.     }
  142.     
  143.     //{ extract the text descriptor }
  144.     err = AEGetParamDesc(ae, keyAETheData, typeChar, &text);
  145.     if (err != noErr)
  146.     {
  147.         goto cleanup;
  148.     }
  149.     
  150.     //{ get total length of text in the active input area }
  151.     totalLength = GetHandleSize(text.dataHandle);
  152.  
  153.     //{ extract the length of confirmed text in the active input area }
  154.     err = AEGetParamPtr(ae, keyAEFixLength, typeLongInteger, &returnedType,
  155.         &fixLength, sizeof(fixLength), &actualSize);
  156.     if (err != noErr)
  157.     {
  158.         goto cleanup;
  159.     }
  160.     //{ if fixLength = -1, all text is confirmed }
  161.     if (fixLength == -1)
  162.     {
  163.         fixLength = totalLength;
  164.     }
  165.     //{ if there's currently no active input area, open one }
  166.     if (pWE->tsmAreaStart == kInvalidOffset)
  167.     {
  168.         pWE->tsmAreaStart = pWE->selStart;
  169.         pWE->tsmAreaEnd = pWE->selEnd;
  170.         
  171.         // { are we tracking a typing sequence? }
  172.         if (WEIsTyping(hWE) == false)
  173.         {
  174.  
  175.             // { nope; so start a new one }
  176.             // { increment modification count }
  177.             pWE->modCount = pWE->modCount + 1;
  178.  
  179.             //{ if undo support is enabled, the inline session just started may initiate }
  180.             if (BTST(pWE->flags, weFUndoSupport))
  181.             {
  182.                 WEClearUndo(hWE);
  183.                 if (WENewAction(pWE->selStart, pWE->selEnd, 0, weAKTyping, 0, hWE, &hAction) == noErr)
  184.                 {
  185.                     if (WEPushAction(hAction) != noErr)
  186.                     {
  187.                         ;
  188.                     }
  189.                 }
  190.             }
  191.         }
  192.     }
  193.  
  194.     tsmOffset = pWE->tsmAreaStart;
  195.  
  196.     //{ the new text replaces whatever is in the active input area }
  197.     err = _WEDeleteRange(tsmOffset, pWE->tsmAreaEnd, hWE);
  198.     if (err != noErr)
  199.     {
  200.         goto cleanup;
  201.     }
  202.  
  203.     //{ synchronize the null style, so font script matches the keyboard script }
  204.     _WESynchNullStyle(hWE);
  205.  
  206.     //{ set the port font for good measure }
  207.     GetPort(&savePort);
  208.     SetPort(pWE->port);
  209.     TextFont(pWE->nullStyle.runStyle.tsFont);
  210.     SetPort(savePort);
  211.  
  212.     //{ temporarily lock the text }
  213.     saveTextLock = _WESetHandleLock(text.dataHandle, true);
  214.  
  215.     // { insert the text }
  216.     err = _WEInsertText(tsmOffset, *(text.dataHandle), totalLength, hWE);
  217.     if (err != noErr)
  218.     {
  219.         goto cleanup;
  220.     }
  221.     //{ unlock the text }
  222.     _WESetHandleLock(text.dataHandle, saveTextLock);
  223.  
  224.     //{ extract pin range }
  225.     err = AEGetParamPtr(ae, keyAEPinRange, typeTextRange, &returnedType, &pinRange,
  226.         sizeof(pinRange), &actualSize);
  227.     if (err == noErr)
  228.     {
  229.         //{ we want absolute offsets }
  230.         pinRange.fStart = pinRange.fStart + tsmOffset;
  231.         pinRange.fEnd = pinRange.fEnd + tsmOffset;
  232.     }
  233.     else
  234.     {
  235.         //{ a missing pin range descriptor isn't an error; everything else is }
  236.         if (err != errAEDescNotFound)
  237.         {
  238.             goto cleanup;
  239.         }
  240.         //{ default pin range is active input area }
  241.         pinRange.fStart = tsmOffset;
  242.         pinRange.fEnd = pWE->tsmAreaEnd;
  243.     }
  244.  
  245.     // { NOTE: if fixLength = totalLength, the inline input session is over, so, in theory, }
  246.     // { hiliteTray should either be missing or not specify any range to be underlined. }
  247.     // { Unfortunately, some input methods (like Apple's input method for Simplified Chinese) }
  248.     // { do specify kConvertedText (= thin black underline) for the whole text when }
  249.     // { the text is confirmed (is this a bug?).  To work around this, we deliberately ignore }
  250.     // { the hiliteTray parameter when fixLength = totalLength. }
  251.  
  252.     if (fixLength != totalLength)
  253.     {
  254.         //{ extract the highlight range array }
  255.         err = AEGetParamDesc(ae, keyAEHiliteRange, typeTextRangeArray, &hiliteTray);
  256.         if (err != noErr)
  257.         {
  258.             if (err != errAEDescNotFound)
  259.             {
  260.                 goto cleanup;
  261.             }
  262.         }
  263.     }
  264.  
  265.     if (hiliteTray.dataHandle != nil)
  266.     {
  267.         err = _WEHiliteRangeArray((TextRangeArrayHandle)hiliteTray.dataHandle, hWE);
  268.         if (err != noErr)
  269.         {
  270.             goto cleanup;
  271.         }
  272.     }
  273.     else
  274.     {
  275.         pWE->selStart = tsmOffset + fixLength;
  276.         pWE->selEnd = pWE->selStart;
  277.     }
  278.  
  279.     //{ temporarily disable auto-scroll, as we need to scroll manually according to pinRange }
  280.     saveAutoScroll = BTST(pWE->flags, weFAutoScroll);
  281.     BCLR(pWE->flags, weFAutoScroll);
  282.     
  283.     //{ redraw the active input area }
  284.     err = _WERedraw(tsmOffset, tsmOffset + totalLength, hWE);
  285.     if (err != noErr)
  286.     {
  287.         goto cleanup;
  288.     }
  289.  
  290.     if (saveAutoScroll)
  291.     {
  292.     
  293.         //{ re-enable auto-scroll }
  294.         BSET(pWE->flags, weFAutoScroll);
  295.  
  296.         //{ scroll the pin range into view }
  297.         if (_WEScrollIntoView(pinRange.fStart, hWE) == false)
  298.         {
  299.             if (pinRange.fStart != pinRange.fEnd)
  300.             {
  301.                 _WEScrollIntoView(pinRange.fEnd, hWE);
  302.             }
  303.         }
  304.     }
  305.  
  306.     //{ update the boundaries of the active input area }
  307.     //{ if fixLength = totalLength, the inline input session is over: close the active input area }
  308.     if (fixLength == totalLength)
  309.     {
  310.         pWE->tsmAreaStart = kInvalidOffset;
  311.         pWE->tsmAreaEnd = kInvalidOffset;
  312.  
  313.         //{ adjust undo buffer (if any) for the confirmed text }
  314.         _WEAdjustUndoRange(fixLength, hWE);
  315.     }
  316.     else
  317.     {
  318.         //{ otherwise, fixLength defines the boundaries of the active input area }
  319.         pWE->tsmAreaStart = tsmOffset + fixLength;
  320.         pWE->tsmAreaEnd = tsmOffset + totalLength;
  321.     }
  322.  
  323.     //{ call the post-update callback, if present }
  324.     if (pWE->tsmPostUpdate != nil)
  325.     {
  326.         CallWETSMPostUpdateProc(hWE, fixLength, pWE->tsmAreaStart, pWE->tsmAreaEnd,
  327.             pinRange.fStart, pinRange.fEnd, (WETSMPostUpdateUPP)pWE->tsmPostUpdate);
  328.     }
  329.     //{ clear result code }
  330.     err = noErr;
  331.  
  332. cleanup:
  333.     //{ clean up }
  334.     AEDisposeDesc(&text);
  335.     AEDisposeDesc(&hiliteTray);
  336.  
  337.     //{ unlock the WE record }
  338.     if (hWE !=NULL)
  339.     {
  340.         _WESetHandleLock((Handle)hWE, saveWELock);
  341.     }
  342.  
  343.     //{ return result code }
  344.     return err;
  345. }
  346.  
  347.  
  348. pascal OSErr _WEHandlePositionToOffset (AppleEvent *ae, AppleEvent *reply,
  349.         long handlerRefCon)
  350. {
  351. #pragma unused(handlerRefCon)
  352.     WEHandle hWE;
  353.     WEPtr pWE;
  354.     Point position;
  355.     LongPt thePoint;
  356.     short regionClass;
  357.     long offset;
  358.     DescType returnedType;
  359.     long actualSize;
  360.     GrafPtr savePort;
  361.     char edge;
  362.     Boolean saveWELock;
  363.     OSErr err;
  364.  
  365.     hWE = nil;
  366.  
  367.     //{ extract WE handle }
  368.     err = AEGetParamPtr(ae, keyAETSMDocumentRefcon, typeLongInteger, &returnedType,
  369.         &hWE, sizeof(hWE), &actualSize);
  370.     if (err != noErr)
  371.     {
  372.         goto cleanup;
  373.     }
  374.  
  375.     //{ lock the WE record }
  376.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  377.     pWE = *hWE;
  378.  
  379.     // { extract position parameter }
  380.     err = AEGetParamPtr(ae, keyAECurrentPoint, myTypeQDPoint, &returnedType, &position,
  381.         sizeof(position), &actualSize);
  382.     if (err != noErr)
  383.     {
  384.             goto cleanup;
  385.     }
  386.     //{ convert position to local... }
  387.     GetPort(&savePort);
  388.     SetPort(pWE->port);
  389.     GlobalToLocal(&position);
  390.     SetPort(savePort);
  391.  
  392.     //{ ...and long coordinates }
  393.     WEPointToLongPoint(position, &thePoint);
  394.  
  395.     //{ find the byte offset and the edge value corresponding to the given position }
  396.     offset = WEGetOffset(&thePoint, &edge, hWE);
  397.  
  398.     //{ determine the region class }
  399.     if (WELongPointInLongRect(&thePoint, &pWE->viewRect))
  400.     {
  401.         if (_WEOffsetInRange(offset, edge, pWE->tsmAreaStart, pWE->tsmAreaEnd))
  402.         {
  403.               regionClass = kTSMInsideOfActiveInputArea;
  404.             // { if the given position is within the active input area, we're supposed to return }
  405.             // { an offset relative to the beginning of this area (thanks, Martin!) }
  406.             offset -= pWE->tsmAreaStart;
  407.         }
  408.         else
  409.         {
  410.             // { otherwise the offset is relative to the beginning of the body }
  411.             regionClass = kTSMInsideOfBody;
  412.         }
  413.     }
  414.     else
  415.     {
  416.         regionClass = kTSMOutsideOfBody;
  417.     }
  418.     
  419.     //{ add region class parameter to reply }
  420.     err = AEPutParamPtr(reply, keyAERegionClass, typeShortInteger, ®ionClass,
  421.         sizeof(regionClass));
  422.     if (err != noErr)
  423.     {
  424.         goto cleanup;
  425.     }
  426.     
  427.     // { add offset parameter to reply }
  428.     err = AEPutParamPtr(reply, keyAEOffset, typeLongInteger, &offset, sizeof(offset));
  429.     if (err != noErr) 
  430.     {
  431.         goto cleanup;
  432.     }
  433.     
  434.     //{ add edge parameter to reply }
  435.     err = AEPutParamPtr(reply, keyAELeftSide, typeBoolean, &edge, sizeof(edge));
  436.     if (err != noErr)
  437.     {
  438.         goto cleanup;
  439.     }
  440.  
  441.     //{ clear result code }
  442.     err = noErr;
  443.  
  444. cleanup:
  445.     //{ unlock the WE record }
  446.     if (hWE != nil)
  447.     {
  448.         _WESetHandleLock((Handle)hWE, saveWELock);
  449.     }
  450.     
  451.     //{ return result code }
  452.     return err;
  453. }
  454.  
  455. pascal OSErr _WEHandleOffsetToPosition(AppleEvent *ae, AppleEvent *reply, long handlerRefCon)
  456. {
  457. #pragma unused(handlerRefCon)
  458.     WEHandle hWE;
  459.     WEPtr pWE;
  460.     long offset;
  461.     LongPt thePoint;
  462.     Point position;
  463.     short lineHeight;
  464.     DescType returnedType;
  465.     long actualSize;
  466.     GrafPtr savePort;
  467.     Boolean saveWELock;
  468.     OSErr err;
  469.  
  470.     hWE = nil;
  471.  
  472.     //{ extract WE handle }
  473.     err = AEGetParamPtr(ae, keyAETSMDocumentRefcon, typeLongInteger, &returnedType, &hWE,
  474.         sizeof(hWE), &actualSize);
  475.     if (err != noErr)
  476.     {
  477.         goto cleanup;
  478.     }
  479.  
  480.     //{ lock the WE record }
  481.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  482.     pWE = *hWE;
  483.  
  484.     //{ if there's no active input area, return errOffsetInvalid }
  485.     if (pWE->tsmAreaStart < 0)
  486.     {
  487.         err = errOffsetInvalid;
  488.         goto cleanup;
  489.     }
  490.     
  491.     //{ extract the offset parameter }
  492.     err = AEGetParamPtr(ae, keyAEOffset, typeLongInteger, &returnedType, &offset, 
  493.         sizeof(offset), &actualSize);
  494.     if (err != noErr)
  495.     {
  496.         goto cleanup;
  497.     }
  498.  
  499.     //{ offset is relative to the beginning of the active input area; we want an absolute offset }
  500.     offset = offset + pWE->tsmAreaStart;
  501.  
  502.     // { make sure the offset is within the input area }
  503.     if ((offset < pWE->tsmAreaStart) || (offset >= pWE->tsmAreaEnd))
  504.     {
  505.         err = errOffsetInvalid;
  506.         goto cleanup;
  507.     }
  508.  
  509.     //{ find the position corresponding to the given offset (in long coordinates) }
  510.     WEGetPoint(offset, &thePoint, &lineHeight, hWE);
  511.     thePoint.v = thePoint.v + lineHeight;
  512.  
  513.     //{ make sure offset is within view rectangle }
  514.     if (!WELongPointInLongRect(&thePoint, &pWE->viewRect))
  515.     {
  516.         err = errOffsetIsOutsideOfView;
  517.         goto cleanup;
  518.     }
  519.  
  520.     //{ convert the point to short... }
  521.     WELongPointToPoint(&thePoint, &position);
  522.  
  523.     //{ ...and global coordinates }
  524.     GetPort(&savePort);
  525.     SetPort(pWE->port);
  526.     LocalToGlobal(&position);
  527.     SetPort(savePort);
  528.  
  529.     //{ add keyAEPoint parameter to the reply Apple event }
  530.     err = AEPutParamPtr(reply, keyAEPoint, myTypeQDPoint, &position, sizeof(position));
  531.     if (err != noErr)
  532.     {
  533.         goto cleanup;
  534.     }
  535.  
  536.     //{ add keyAETSMTextFont parameter to the reply Apple event }
  537.     err = AEPutParamPtr(reply, keyAETSMTextFont, typeShortInteger, &pWE->nullStyle.runStyle.tsFont,
  538.         sizeof(pWE->nullStyle.runStyle.tsFont));
  539.     if (err != noErr)
  540.     {
  541.         goto cleanup;
  542.     }
  543.     
  544.     //{ add keyAETSMTextPointSize parameter to the reply Apple event }
  545.     err = AEPutParamPtr(reply, keyAETSMTextPointSize, typeShortInteger, 
  546.         &pWE->nullStyle.runStyle.tsSize, sizeof(pWE->nullStyle.runStyle.tsSize));
  547.     if (err != noErr)
  548.     {
  549.         goto cleanup;
  550.     }
  551.  
  552.     //{ add keyAETextLineAscent parameter to the reply Apple event }
  553.     err = AEPutParamPtr(reply, keyAETextLineAscent, typeShortInteger, 
  554.         &pWE->nullStyle.runAscent, sizeof(pWE->nullStyle.runAscent));
  555.     if (err != noErr)
  556.     {
  557.         goto cleanup;
  558.     }
  559.     
  560.     //{ add keyAETextLineHeight parameter to the reply Apple event }
  561.     err = AEPutParamPtr(reply, keyAETextLineHeight, typeShortInteger, 
  562.         &pWE->nullStyle.runHeight, sizeof(pWE->nullStyle.runHeight));
  563.     if (err != noErr)
  564.     {
  565.         goto cleanup;
  566.     }
  567.     
  568.     //{ clear result code }
  569.     err = noErr;
  570.  
  571. cleanup:
  572.     //{ unlock the WE record }
  573.     if (hWE != nil)
  574.     {
  575.         _WESetHandleLock((Handle) hWE, saveWELock);
  576.     }
  577.     
  578.     //{ return result code }
  579.     return err;
  580. }
  581.  
  582. pascal OSErr WEInstallTSMHandlers(void)
  583. {
  584.     OSErr err;
  585.     
  586.     // { the first time we're called, create routine descriptors for our Apple event handlers }
  587.     if (_weUpdateActiveInputAreaHandler == nil)
  588.     {
  589.         _weUpdateActiveInputAreaHandler = NewAEEventHandlerProc(_WEHandleUpdateActiveInputArea);
  590.         _wePositionToOffsetHandler = NewAEEventHandlerProc(_WEHandlePositionToOffset);
  591.         _weOffsetToPositionHandler = NewAEEventHandlerProc(_WEHandleOffsetToPosition);
  592.     }
  593.  
  594.     //{ install Apple Event handlers to be used by Text Service components }
  595.     err = AEInstallEventHandler(kTextServiceClass, kUpdateActiveInputArea,
  596.         _weUpdateActiveInputAreaHandler, 0, false);
  597.     if (err != noErr)
  598.     {
  599.         return err;
  600.     }
  601.         
  602.     err = AEInstallEventHandler(kTextServiceClass, kPos2Offset, 
  603.         _wePositionToOffsetHandler, 0, false);
  604.     if (err != noErr)
  605.     {
  606.         return err;
  607.     }
  608.     
  609.     err = AEInstallEventHandler(kTextServiceClass, kOffset2Pos, 
  610.         _weOffsetToPositionHandler, 0, false);
  611.     if (err != noErr)
  612.     {
  613.         return err;
  614.     }
  615.     
  616.     // { return result code }
  617.     return noErr;
  618. }
  619.  
  620. pascal OSErr WERemoveTSMHandlers(void)
  621. {
  622.     OSErr err;
  623.     
  624.     // { return an error code if WEInstallTSMHandlers has never been called }
  625.     if (_weUpdateActiveInputAreaHandler == nil)
  626.         return errAEHandlerNotFound;
  627.  
  628.     // { remove the handlers }
  629.     err = AERemoveEventHandler(kTextServiceClass, kUpdateActiveInputArea,
  630.         _weUpdateActiveInputAreaHandler, false);
  631.     if (err != noErr)
  632.     {
  633.         return err;
  634.     }
  635.         
  636.     err = AERemoveEventHandler(kTextServiceClass, kPos2Offset, 
  637.         _wePositionToOffsetHandler, false);
  638.     if (err != noErr)
  639.     {
  640.         return err;
  641.     }
  642.     
  643.     err = AERemoveEventHandler(kTextServiceClass, kOffset2Pos, 
  644.         _weOffsetToPositionHandler, false);
  645.     if (err != noErr)
  646.     {
  647.         return err;
  648.     }
  649.     
  650.     // { clear result code }
  651.     return noErr;
  652. } // { WERemoveTSMHandlers }
  653.